#!/usr/bin/perl -w
use warnings;
use strict;

#require 'cpreport-common.pl';

# =============================================================================
# ==  C O N D I T I O N S
# =============================================================================
my $cond_tma3c = sub {
    my ($ic) = @_;
    return 1
        # reset current
        && $ic->{Idd_reset}     <= 0.1          # mA
        # display voltages
        && 1.4 <= $ic->{VDD18C_display}
        &&        $ic->{VDD18C_display} <= 2.3
        && $ic->{VCOMH_display} >= 3.1
        && $ic->{VCOML_display} <= -0.9
        && $ic->{VLCDC_display} >= 4.5
        && $ic->{VGHC_display}  >= 12
        && $ic->{VGLC_display}  <= -5
        && $ic->{Idd_display}   <= 10
        # RAM/register
        && $ic->{Register_read} eq 'P'
        && $ic->{RAM_cb}        eq 'P'
        && $ic->{RAM_one}       eq 'P'
        && $ic->{RAM_zero}      eq 'P'
        && $ic->{RAM_gs}        eq 'P'
        # dispay timing;
        && $ic->{DisplayTiming} eq 'P';
};

my $cond_1 = sub {
    my ($ic) = @_;
    return 1
        && 1.4 <= $ic->{VDD18C_display}
        &&        $ic->{VDD18C_display} <= 2.3
        && $ic->{VCOMH_display} >= 3.1
        && $ic->{VCOML_display} <= -0.9
        && $ic->{VLCDC_display} >= 4.5
        && $ic->{VGHC_display}  >= 12
        && $ic->{VGLC_display}  <= -5
        && $ic->{Idd_display}   <= 10
        && $ic->{RAM_cb}        eq 'P'
        && $ic->{RAM_one}       eq 'P'
        && $ic->{RAM_zero}      eq 'P'
        # && $ic->{RAM_gs}       eq 'P';
};

# =============================================================================
# ==  C A L C U L A T I O N  D A T A
# =============================================================================

my $sub_RAM_all = sub {
    my ($ic) = @_;
    return 1
        && $ic->{RAM_cb} eq 'P'
        && $ic->{RAM_one} eq 'P'
        && $ic->{RAM_zero} eq 'P'
        #&& $ic->{RAM_gs} eq 'P'
        ? 'P' : 'F';
};

my $sub_Register_RAM = sub {
    my ($ic) = @_;
    return 1
        && $ic->{Register_read} eq 'P'
        && $sub_RAM_all->($ic)
        ? 'P' : 'F';
};

# =============================================================================
# ==  R A N G E S
# =============================================================================

my $rng_Idd_reset_0 = [ 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 5, 10, ];
my $rng_Idd_reset_1 = [ 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 1, 2, 3, 4, 5, 10, 50, 100, ];

my $rng_Idd_display_0 = [ 1, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 10 ];
my $rng_Idd_display_1 = [ 0.1, 0.5, 1, 2, 2.5, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10, 20, 50, 100, ];

my $rng_I_PIN_display_0 = [ 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 1, 2, 5, 10, 20, 30, 50, ];
my $rng_I_PIN_display_1 = [ 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 1, 2, 5, 10, 20, 30, 50, ];

my $rng_VDD18C_display_0 = [ 1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.4 ];
my $rng_VDD18C_display_1 = [ 1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.4, 2.5, 2.7, 2.9 ];

my $rng_VCOMH_display_0  = [ 2, 2.5, 3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5 ];
my $rng_VCOMH_display_1  = [ 2, 2.5, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 5 ];

my $rng_VCOML_display_0  = [ -2, -1.8, -1.6, -1.5, -1.4, -1.2, -1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.1, ];
my $rng_VCOML_display_1  = [ -2, -1.8, -1.7, -1.6, -1.5, -1.4, -1.2, -1, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.1, ];

my $rng_VGHC_display_0   = [ 8, 9, 10, 10.5, 11, 11.5, 12, 12.5, 13, 13.5, 14, 14.5, 15, 16, 17, 18 ];
my $rng_VGHC_display_1   = [ 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 ];

my $rng_VGLC_display_0   = [ -9, -8.5, -8, -7.5, -7, -6.5, -6, -5.5, -5, -4.5, -4, -3, -2, -1 ];
my $rng_VGLC_display_1   = [ -16, -15, -14, -13, -12, -10, -9, -8, -7, -6, -5, -4, -3, -1, ];

my $rng_VLCDC_display_0  = [ 3, 3.5, 4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 6 ];
my $rng_VLCDC_display_1  = [ 3, 3.5, 4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 6 ];

my $rng_VCLC_display_0 = [ -3, -2.9, -2.8, -2.7, -2.6, -2.5, -2.4, -2.3, -2.2, -2, -1 ];
my $rng_VCLC_display_1 = [ -3, -2.9, -2.8, -2.7, -2.6, -2.5, -2.4, -2.3, -2.2, -2, -1 ];

my $rng_VCI1_display_0 = [ 2, 2.2, 2.4, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3 ];
my $rng_VCI1_display_1 = [ 2, 2.2, 2.4, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8 ];

my $rng_VGAM1OUT_display_0 = [ 3.5, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, ];
my $rng_VGAM1OUT_display_1 = [ 2, 3, 3.5, 4, 4.2, 4.4, 4.6, 4.8, 5, 5.2, 5.3, 5.4, 5.5, 6 ];

## universal initialization repository
my %ranges = (
    ## reset current
    Idd_reset        => [ $rng_Idd_reset_0, $rng_Idd_reset_1, ],
    I_VCI_reset      => 'Idd_reset', I_VCC_reset => 'Idd_reset', I_IOVCC_reset => 'Idd_reset',
    ## operation current
    Idd_display      => [ $rng_Idd_display_0,      $rng_Idd_display_1,    ],
    I_VCI_display    => 'Idd_display',
    I_VCC_display    => [ $rng_I_PIN_display_0,    $rng_I_PIN_display_1,  ],
    I_IOVCC_display  => 'I_VCC_display',
    ## operation voltages
    VDD18C_display   => [ $rng_VDD18C_display_0,   $rng_VDD18C_display_1, ],
    #-
    VCOMH_display    => [ $rng_VCOMH_display_0,    $rng_VCOMH_display_1,  ],
    VCOML_display    => [ $rng_VCOML_display_0,    $rng_VCOML_display_1,  ],
    #-
    VGHC_display     => [ $rng_VGHC_display_0,     $rng_VGHC_display_1,   ],
    VGLC_display     => [ $rng_VGLC_display_0,     $rng_VGLC_display_1,   ],
    #-
    VLCDC_display    => [ $rng_VLCDC_display_0,    $rng_VLCDC_display_1,  ],
    #-
    VCLC_display     => [ $rng_VCLC_display_0,     $rng_VCLC_display_1,   ],
    #-
    VCI1_display     => [ $rng_VCI1_display_0,     $rng_VCI1_display_1,   ],
    #-
    VGAM1OUT_display => [ $rng_VGAM1OUT_display_0, $rng_VGAM1OUT_display_1,   ],
);
## also set for DC/DC1 DC/DC23 and DC/DC4
my @display_params = grep $_ =~ /_display$/, keys %ranges;
for my $stage ( qw( dc1 dc23 dc4 display2 ) ) {
    for my $param ( @display_params ) {
        (my $stage_param = $param) =~ s/_display$/_${stage}/;
        $ranges{$stage_param} = $ranges{$param};
    }
}
for (keys %ranges) {
    if (ref $ranges{$_} ne 'ARRAY') {
        my $refer = $ranges{$_};
        if (exists $ranges{$refer}) {
            $ranges{$_} = $ranges{$refer};
        } else {
            die "ERROR: $refer: range specification invalid.";
        }
    }
}

## modes
my %modes = map(
    {;
        $_ => (
            $_ =~ /^I(?:dd_|_VCI|_VCC|_IOVCC)/ ?     3 # current
                : $_ =~ /^(?:VCLC_|VCOML_|VGLC_)/  ? 1 # negative voltages
                : 0 # normal voltages
        );
    } keys %ranges
);
############ the repository

my $rng_select = 1;

my $repo = [
    #+{ item => 'Idd_reset',        mode => -1, ranges => $rng_select, condition => $cond_1, },
    #+{ item => 'I_VCI_reset',      mode => -1, ranges => $rng_select, condition => $cond_1, },
    #+{ item => 'I_VCC_reset',      mode => -1, ranges => $rng_select, condition => $cond_1, },
    #+{ item => 'I_IOVCC_reset',    mode => -1, ranges => $rng_select, condition => $cond_1, },
    # -------------------------------------------------------------------------
    +{ item => 'Idd_reset',        mode => -1, ranges => $rng_select, },
    +{ item => 'I_VCI_reset',      mode => -1, ranges => $rng_select, },
    +{ item => 'I_VCC_reset',      mode => -1, ranges => $rng_select, },
    +{ item => 'I_IOVCC_reset',    mode => -1, ranges => $rng_select, },
    # -------------------------------------------------------------------------
    +{ item => 'I_VCI_display',    mode => -1, ranges => $rng_select, },
    +{ item => 'I_VCC_display',    mode => -1, ranges => $rng_select, },
    +{ item => 'I_IOVCC_display',  mode => -1, ranges => $rng_select, },
    +{ item => 'Idd_display',      mode => -1, ranges => $rng_select, },
    # -------------------------------------------------------------------------
    ## RAM
    +{ item => 'Register_read',    mode => -1, },
    +{ item => 'RAM_cb',           mode => -1, },
    +{ item => 'RAM_one',          mode => -1, },
    +{ item => 'RAM_zero',         mode => -1, },
    #+{ item => 'RAM_gs',           mode => -1, },
    +{ item => 'DisplayTiming',    mode => -1, },
    +{ item => $sub_RAM_all,       mode => 4, desc => 'RAM_all', },
    +{ item => $sub_Register_RAM,  mode => 4, desc => 'Register_and_RAM', },
    ## voltages of dc4/display on
    +{ item => 'VDD18C_dc4',       mode => -1, ranges => $rng_select, },
    +{ item => 'VDD18C_display',   mode => -1, ranges => $rng_select, },
    +{ item => 'VDD18C_display2',   mode => -1, ranges => $rng_select, },
    +{ item => 'VCOMH_dc4',        mode => -1, ranges => $rng_select, },
    +{ item => 'VCOMH_display',    mode => -1, ranges => $rng_select, },
    +{ item => 'VCOMH_display2',    mode => -1, ranges => $rng_select, },
    +{ item => 'VCOML_dc4',        mode => -1, ranges => $rng_select, },
    +{ item => 'VCOML_display',    mode => -1, ranges => $rng_select, },
    +{ item => 'VCOML_display2',    mode => -1, ranges => $rng_select, },
    +{ item => 'VGHC_dc4',         mode => -1, ranges => $rng_select, },
    +{ item => 'VGHC_display',     mode => -1, ranges => $rng_select, },
    +{ item => 'VGHC_display2',     mode => -1, ranges => $rng_select, },
    +{ item => 'VGLC_dc4',         mode => -1, ranges => $rng_select, },
    +{ item => 'VGLC_display',     mode => -1, ranges => $rng_select, },
    +{ item => 'VGLC_display2',     mode => -1, ranges => $rng_select, },
    +{ item => 'VLCDC_dc4',        mode => -1, ranges => $rng_select, },
    +{ item => 'VLCDC_display',    mode => -1, ranges => $rng_select, },
    +{ item => 'VLCDC_display2',    mode => -1, ranges => $rng_select, },
    +{ item => 'VCLC_dc4',         mode => -1, ranges => $rng_select, },
    +{ item => 'VCLC_display',     mode => -1, ranges => $rng_select, },
    +{ item => 'VCI1_dc4',         mode => -1, ranges => $rng_select, },
    +{ item => 'VCI1_display',     mode => -1, ranges => $rng_select, },
    +{ item => 'VGAM1OUT_dc4',     mode => -1, ranges => $rng_select, },
    +{ item => 'VGAM1OUT_display', mode => -1, ranges => $rng_select, },
];

my %mode_of_name = (
    VDD18C_ => 0,
    VCOMH_  => 0,
    VCOML_  => 1,
    VGHC_   => 0,
    VGLC_   => 1,
    VLCDC_  => 0,
    VCLC_   => 1,
    VGAM1OUT_ => 0,
    I_      => 3,
    Idd_    => 3,
);

for (@$repo) {
    if ($_->{mode} == -1) {
        if ($_->{item} =~ /(?:^S?RAM_|Register|DisplayTiming|OpenShort|^OS_)/) {
            $_->{mode} = 4;
        } else {
            if (defined $modes{ $_->{item} } ) {
                $_->{mode} = $modes{ $_->{item} };
            } else {
                for my $prefix (keys %mode_of_name) {
                    my $len = length($prefix);
                    if (substr( $_->{item}, 0, $len ) eq $prefix) {
                        $_->{mode} = $mode_of_name{$prefix};
                        last;
                    }
                }
                die "cannot deduce mode for item: $_->{item}" if ($_->{mode} < 0);
            }
        }
    }
    if (defined $_->{ranges} && ref $_->{ranges} ne 'ARRAY') {
        my $sel = $_->{ranges};
        my $item_name = $_->{item};
        #print "item: $item_name\n";
        die "ERROR: item [$item_name]: not a scalar." if ref $item_name;
        die "ERROR: $sel: invalid range selection." if ref($ranges{ $item_name }[ $sel ]) ne 'ARRAY';
        $_->{ranges} = $ranges{ $item_name }[ $sel ];
    }
}

$repo;
